/*******************************************************************************
 * Copyright (c) 2014 Steffen Mikkelsen
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     Steffen Mikkelsen - initial API and implementation
 ******************************************************************************/
package com.subsecret.secureconnection.securestream.layers.gzip;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;

import com.subsecret.secureconnection.securestream.SecureStreamLayer;
import com.subsecret.secureconnection.securestream.stream.gzip.GZIPCompressionOutputStream;
import com.subsecret.secureconnection.streamtools.StreamTools;
import com.subsecret.tuples.Tuple;
import com.subsecret.tuples.Tuple.Tuple2;

public class GZIPCompressionLayer implements SecureStreamLayer {
    
    public String compressionDesc;
    private DeflaterCompression deflaterCompression = DeflaterCompression.DEFAULT_COMPRESSION;
    private DeflaterStrategy deflaterStrategy = DeflaterStrategy.DEFAULT_STRATEGY;
    
    public void setCompressionDesc(String compressionDesc) {
        this.compressionDesc = compressionDesc;
    }
    
    public void setDeflaterCompression(DeflaterCompression deflaterCompression) {
        this.deflaterCompression = deflaterCompression;
    }
    
    public void setDeflaterStrategy(DeflaterStrategy deflaterStrategy) {
        this.deflaterStrategy = deflaterStrategy;
    }
    
    public GZIPCompressionLayer() {
    }
    
    public GZIPCompressionLayer(DeflaterCompression deflaterCompression, DeflaterStrategy deflaterStrategy) {
        this.deflaterCompression = deflaterCompression;
        this.deflaterStrategy = deflaterStrategy;
    }
    
    @Override
    public int getLayerID() {
        return 15;
    }
    
    @Override
    public String getLayerDescription() {
        return "Compression Layer (GZIP: " + deflaterCompression.name() + " / " + deflaterStrategy.name() + ")";
    }
    
    public static enum DeflaterCompression {
        DEFAULT_COMPRESSION(Deflater.DEFAULT_COMPRESSION), BEST_COMPRESSION(Deflater.BEST_COMPRESSION), BEST_SPEED(Deflater.BEST_SPEED);
        
        public byte val;
        
        DeflaterCompression(int val) {
            this.val = (byte) val;
        }
    }
    
    public static enum DeflaterStrategy {
        DEFAULT_STRATEGY(Deflater.DEFAULT_STRATEGY), FILTERED(Deflater.FILTERED), HUFFMAN_ONLY(Deflater.HUFFMAN_ONLY);
        
        public byte val;
        
        DeflaterStrategy(int val) {
            this.val = (byte) val;
        }
    }
    
    @Override
    public Tuple2<InputStream, OutputStream> createLayerServer(InputStream in, OutputStream out) throws IOException {
        
        // Receive method and strategy
        byte deflaterCompression = StreamTools.receiveByte(in);
        byte deflaterStrategy = StreamTools.receiveByte(in);
        
        in = new GZIPInputStream(in);
        out = new GZIPCompressionOutputStream(out, deflaterCompression, deflaterStrategy);
        out.flush();
        return Tuple.of(in, out);
    }
    
    @Override
    public Tuple2<InputStream, OutputStream> createLayerClient(InputStream in, OutputStream out) throws IOException {
        
        // Send method and strategy
        StreamTools.sendByte(out, deflaterCompression.val, false);
        StreamTools.sendByte(out, deflaterStrategy.val);
        
        out = new GZIPCompressionOutputStream(out, deflaterCompression, deflaterStrategy);
        out.flush();
        in = new GZIPInputStream(in);
        
        return Tuple.of(in, out);
    }
    
}
